#ifndef CCOMPILER_H
#define CCOMPILER_H

#include <QString>
#include <QStringList>
#include <QHash>

#include "utils/CByteArray.h"

class CCompiler
{
private:
    static constexpr auto OPERATION_CODE_COMMENT = "#";

    static constexpr auto OPERATION_CODE_PUSH = "push";
    static constexpr auto OPERATION_CODE_POP = "pop";
    static constexpr auto OPERATION_CODE_BIND = "bind";
    static constexpr auto OPERATION_CODE_GET_VAR = "get_var";

    static constexpr auto OPERATION_CODE_IF = "if";
    static constexpr auto OPERATION_CODE_GO_TO = "go_to";
    static constexpr auto OPERATION_CODE_FUNC = "func";
    static constexpr auto OPERATION_CODE_CALL = "call";
    static constexpr auto OPERATION_CODE_RET = "ret";
    static constexpr auto OPERATION_CODE_END = "end";

    static constexpr auto OPERATION_CODE_OR = "or";
    static constexpr auto OPERATION_CODE_AND = "and";
    static constexpr auto OPERATION_CODE_NOT = "not";

    static constexpr auto OPERATION_CODE_EQ = "eq";
    static constexpr auto OPERATION_CODE_NEQ = "neq";
    static constexpr auto OPERATION_CODE_GTE = "gte";
    static constexpr auto OPERATION_CODE_GT = "gt";
    static constexpr auto OPERATION_CODE_LTE = "lte";
    static constexpr auto OPERATION_CODE_LT = "lt";

    static constexpr auto OPERATION_CODE_ADD = "add";
    static constexpr auto OPERATION_CODE_SUB = "sub";
    static constexpr auto OPERATION_CODE_MUL = "mul";
    static constexpr auto OPERATION_CODE_DIV = "div";


    QString path;
    CByteArray byteArray;
    QHash<QString, void (CCompiler::*)(QStringList&)> parsers;
    int lineNumber = 1;
    QString line;

public:
    CCompiler(QString path);

    CByteArray compile();

private:
    void parse(QString string);

    void push(QStringList& parts);
    void pop(QStringList&);
    void bind(QStringList&);
    void getVar(QStringList&);


    void if_(QStringList&);
    void goTo(QStringList&);
    void func(QStringList&);
    void invoke(QStringList&);
    void ret(QStringList&);
    void end(QStringList&);

    void or_(QStringList&);
    void and_(QStringList&);
    void not_(QStringList&);

    void eq(QStringList&);
    void neq(QStringList&);
    void gte(QStringList&);
    void gt(QStringList&);
    void lte(QStringList&);
    void lt(QStringList&);

    void add(QStringList&);
    void sub(QStringList&);
    void mul(QStringList&);
    void div(QStringList&);

    void pushInt(int value);
    void pushTypeNumber(double value);
    void pushString(QString& value);
    void pushNull();
    void pushFalse();
    void pushTrue();
};

#endif
